package com.sensoro.beacon.kit;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

/**
 * 最外层数据组装，拆包与组装包 主要用于组装CMD_R_CFG CMD_W_CFG 两个命令
 * 
 * @author sensoro
 * 
 */
class Analyse_0_1 implements IAnalyse {

	int protocolVersion;
	int hardwareVersion;

	int dataLocation;
	int packageNum = 0;
	int dataLeanth;
	private byte[] readData;
	/**
	 * 是否在读取中，在读取中需要使用dataLocation
	 */
	private boolean readFlage = false;

	public Analyse_0_1(int protocolVersion) {
		this.protocolVersion = protocolVersion;
	}

	/**
	 * 组装读数据命令特征值byte[]
	 */
	@Override
	public byte[] combineReadCmd() {
		byte[] readStampByte = new byte[4];
		readStampByte[0] = (byte) protocolVersion;
		readStampByte[1] = 1;
		readStampByte[2] = 0;
		readStampByte[3] = AnalyseFactory.CMD_R_CFG;
		return readStampByte;
	}

	/**
	 * 解析cdm数据
	 * 
	 * @param data
	 * @return
	 */
	@Override
	public BeaconConfiguration analysisCmd(byte[] data) {
		if (data != null) {
			byte[] allata = dataStitching(data);
			if (allata != null) {
				CmdBean bean = splitData(allata);
				if (bean.errorCode == AnalyseFactory.ERROR_CODE_SUCCESS) {
					BeaconConfiguration beacon = analyticlDataLisToBeacon(bean.dataList);
					return beacon;
				} else {
					return null;
				}
			} else {
				return null;
			}
		} else {
			return null;
		}
	}

	/***
	 * 将 Beacon 对象组装成为写特征值所需的byte[]数组
	 * 
	 * @param config
	 * @return
	 */
	@Override
	public ArrayList<byte[]> combineDataPackages(BeaconConfiguration config) {
		// TODO
		if (config != null) {
			CmdBean bean = new CmdBean();
			bean.cmdType = AnalyseFactory.CMD_W_CFG;
			bean.dataList = analyticlBeaconToDataList(config);
			byte[] complete = combineIntactWriteData(bean);
			ArrayList<byte[]> writeDataPackages = splitPackages(complete);
			return writeDataPackages;
		} else {
			return null;
		}
	}

	/**
	 * 将读取到的数据解析成数据类 CmdBean
	 * 
	 * @param allData
	 * @return
	 */
	private CmdBean splitData(byte[] allData) {
		if (allData != null) {
			CmdBean bean = new CmdBean();
			bean.cmdType = allData[3];
			byte[] errorCodeByte = new byte[2];
			System.arraycopy(allData, 4, errorCodeByte, 0, 2);
			bean.errorCode = TransformUtils.bytesToInt(errorCodeByte, 0);
			byte[] dataListByte = new byte[allData.length - 6];
			System.arraycopy(allData, 6, dataListByte, 0, allData.length - 6);
			bean.dataList = getDataList(dataListByte);
			return bean;
		} else {
			return null;
		}
	}

	/**
	 * 将数据内容byte[]数组，差分成ArrayList<byte[]>
	 * 
	 * @param dataListByte
	 * @return
	 */
	private ArrayList<byte[]> getDataList(byte[] dataListByte) {
		if (dataListByte != null) {
			ArrayList<byte[]> list = new ArrayList<byte[]>();
			for (int i = 0; i < dataListByte.length;) {
				int dataLenth = dataListByte[i];
				byte[] item = new byte[dataLenth + 1];
				System.arraycopy(dataListByte, i, item, 0, dataLenth + 1);
				list.add(item);
				i = i + dataLenth + 1;
			}
			return list;
		} else {
			return null;
		}

	}

	/**
	 * 组装读取的数据，读特征值时，不停调用此方法,全部读完返回byte[],未读完返回null
	 * 
	 * @param data
	 * @return isFinish
	 */
	private byte[] dataStitching(byte[] data) {
		if (data != null) {
			if (!readFlage) {
				if (data[0] == protocolVersion) {
					byte[] dataLenthByte = new byte[2];
					System.arraycopy(data, 1, dataLenthByte, 0, 2);
					dataLeanth = TransformUtils.bytesToInt(dataLenthByte, 0) + 3;
					readData = new byte[dataLeanth];
					while (dataLeanth > 20) {
						packageNum++;
						dataLeanth = dataLeanth - 20;
					}
					readFlage = true;
					dataLocation = 1;
					System.arraycopy(data, 0, readData, 0, 20);
				}
				return null;
			} else {
				int readLenth = dataLocation * 20;
				if (dataLocation < packageNum) {
					System.arraycopy(data, 0, readData, readLenth, 20);
					dataLocation++;
					return null;
				} else {
					System.arraycopy(data, 0, readData, readLenth, readData.length - readLenth);
					readFlage = false;
					return readData;
				}
			}
		} else {
			return null;
		}
	}

	/**
	 * 组装完整的写数据特征值 byte[]
	 * 
	 * @param bean
	 * @return
	 */
	private byte[] combineIntactWriteData(CmdBean bean) {
		if (bean != null) {
			byte[] completeData;
			int dataLenth = 0;
			for (byte[] b : bean.dataList) {
				dataLenth = dataLenth + b.length;
			}
			dataLenth = dataLenth + 4;
			completeData = new byte[dataLenth];
			completeData[0] = (byte) protocolVersion;
			byte[] completeLenth = new byte[2];
			completeLenth = TransformUtils.intToBytes(dataLenth - 3);
			System.arraycopy(completeLenth, 0, completeData, 1, 2);
			completeData[3] = AnalyseFactory.CMD_W_CFG;
			int loction = 4;
			for (int i = 0; i < bean.dataList.size(); i++) {
				byte[] item = bean.dataList.get(i);
				System.arraycopy(item, 0, completeData, loction, item.length);
				loction = loction + item.length;
			}
			return completeData;
		} else {
			return null;
		}
	}

	/**
	 * 将完整的写数据特征值，拆分成以20字节为单位的byte[]集合
	 * 
	 * @param complete
	 * @return
	 */
	private ArrayList<byte[]> splitPackages(byte[] complete) {
		if (complete != null) {
			ArrayList<byte[]> writeDataPackages = new ArrayList<byte[]>();
			for (int i = 0; i < complete.length; i = i + 20) {
				if (complete.length <= i + 20) {
					byte[] onePackage = new byte[complete.length - i];
					System.arraycopy(complete, i, onePackage, 0, complete.length - i);
					writeDataPackages.add(onePackage);
				} else {
					byte[] onePackage = new byte[20];
					System.arraycopy(complete, i, onePackage, 0, 20);
					writeDataPackages.add(onePackage);
				}
			}
			return writeDataPackages;
		} else {
			return null;
		}
	}

	/**
	 * 将 ArrayList<byte[]> Beacon 对象解析成用来组装写数据的特征值
	 */
	public BeaconConfiguration analyticlDataLisToBeacon(ArrayList<byte[]> dataList) {
		// 一次遍历s
		if (dataList != null) {
			BeaconConfiguration beacon = null;
			try {
				beacon = new BeaconConfiguration.Builder().creat();
			} catch (Exception e) {
				e.printStackTrace();
			}
			if (beacon != null) {
				for (int i = 0; i < dataList.size(); i++) {
					byte[] item = dataList.get(i);
					switch (item[1]) {
					case AnalyseFactory.TYPE_UUID:
						beacon.setUuid(TransformUtils.bytesToHexString(getItemData(item)));
						break;
					case AnalyseFactory.TYPE_MAJOR:
						beacon.setMajor(TransformUtils.bytesToInt2(getItemData(item), 0));
						break;
					case AnalyseFactory.TYPE_MINOR:
						beacon.setMinor(TransformUtils.bytesToInt2(getItemData(item), 0));
						break;

					default:
						break;
					}
				}
			}
			return beacon;
		} else {
			return null;
		}
	}

	/**
	 * 取出item中的真正数据 例如 03，01，27，11 取出 27，11
	 * 
	 * @param item
	 * @return
	 */
	private byte[] getItemData(byte[] item) {

		byte[] dataItem = new byte[item[0] - 1];
		System.arraycopy(item, 2, item, 0, item[0] - 1);
		return dataItem;
	}

	/**
	 * 将 Beacon 对象解析成ArrayList<byte[]> 用来组装写数据的特征值
	 */
	private ArrayList<byte[]> analyticlBeaconToDataList(BeaconConfiguration config) {
		// 一次遍历
		// for (int i = 0; i < config.backupDatas.size(); i++) {
		// int
		// }
		//
		ArrayList<byte[]> list = new ArrayList<byte[]>();
		Iterator iter = config.backupDatas.entrySet().iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry) iter.next();
			int key = (int) entry.getKey();
			Object val = entry.getValue();
			boolean isAdd = false;// 如果第一次循环添加成功 continue
			for (int type : BeaconConfiguration.integerType) {// 循环 int type
				if (type == key) {
					int value = (int) val;
					byte[] valueByte = TransformUtils.intToBytes2(value);
					byte[] item = new byte[valueByte.length + 2];
					item[0] = (byte) (valueByte.length + 1);
					item[1] = (byte) type;
					System.arraycopy(valueByte, 0, item, 2, 2);
					list.add(item);
					isAdd = true;
					break;
				}
			}
			if (isAdd) {// 如果添加成功 continue
				continue;
			}
			for (int type : BeaconConfiguration.stringType) {// 循环 String type
				if (type == key) {
					String value = (String) val;
					byte[] valueByte = TransformUtils.hexStringToByte(value);
					byte[] item = new byte[valueByte.length + 2];
					item[0] = (byte) (valueByte.length + 1);
					item[1] = (byte) type;
					System.arraycopy(valueByte, 0, item, 2, 2);
					list.add(item);
					isAdd = true;
					break;
				}
			}

		}
		return list;
	}

	class CmdBean {
		int cmdType;
		int errorCode;
		ArrayList<byte[]> dataList;
	}

}
